package org.example.springsecurity0317.filter;

import io.jsonwebtoken.*;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.example.springsecurity0317.Service.impl.UserServiceImpl;
import org.example.springsecurity0317.controller.UserController;
import org.example.springsecurity0317.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.ArrayList;

@Component
public class JwtFilter extends OncePerRequestFilter {
    @Autowired
    UserServiceImpl userServiceImpl;
    @Autowired
    RedisTemplate redisTemplate;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String url=request.getRequestURI();
        if(!url.startsWith("/api")){
            filterChain.doFilter(request,response);
            return;
        }
        //1.从请求的请求头获取前端传过来的token
        String token=resolverToken(request);
        if(token !=null && validateToken(token)){
            //从token里面取信息
            String username = getUsernameFromToken(token);
            User user=(User)redisTemplate.opsForValue().get("login:"+username);
            //打印
            System.out.println(user);

            if(user!=null){
                UserDetails userDetails = userServiceImpl.loadUserByUsername(user.getName());
                //todo: 去数据库中拿到用户的权限信息（优化去redis中）
                //生成AuthenticationToken（是能让后续放行的门票）
                UsernamePasswordAuthenticationToken authToken=new
                        UsernamePasswordAuthenticationToken(user,null,userDetails.getAuthorities());
                //上面的门票放在securityContext（security环境）中
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }

        }
        filterChain.doFilter(request,response);


        /*//1,获取token
        String authorization = request.getHeader("Authorization");
        String token = authorization.substring(7);*/

        //2,验证token有效性
        /*Jws<Claims> claimsJws = Jwts.parser().setSigningKey(UserController.key).parseClaimsJws(token);
        Claims body = claimsJws.getBody();
        if (body==null){
            throw new RuntimeException("error");
        }
        String sub = (String) body.get("sub");
        String username =(String) body.get("username");
        System.out.println("id:"+sub+",name:"+username);
        //3.到得到用户信息
        UserDetails userDetails = userService.loadUserByUsername(username);
        //4.生成。。。。（凭证）
        UsernamePasswordAuthenticationToken authToken=new
                UsernamePasswordAuthenticationToken(username,userDetails.getPassword(),new ArrayList<>(){});
        //5.把凭证放到SecurityContextHolder环境里,（在于后续放行）
        SecurityContextHolder.getContext().setAuthentication(authToken);
        //6.此过滤器执行完毕，放行到下一个过滤器
        filterChain.doFilter(request,response);*/
    }

    /**
     * 从请求头中解析token
     * @return
     */
    private String resolverToken(HttpServletRequest request){
        // 1、从请求的请求头获取前端传过来的token
        String authorization = request.getHeader("Authorization");
        if(authorization != null && authorization.startsWith("Bearer ")){
            return authorization.substring(7);
        }
        return null;
    }

    /**
     * 验证token是否有效
     * @param token
     * @return
     */
    private boolean validateToken(String token){
        try{
            Jwts.parser().setSigningKey(UserController.key).parseClaimsJws(token);//这行代码不报错就说明token有效
            return true;//token有效
        }catch (Exception e){
            e.printStackTrace();
            return false;//token无效
        }

    }

    /**
     * 从token里面获取subject（对应的值就是存进去的username）
     * @param token
     * @return
     */
    private String getUsernameFromToken(String token){
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(UserController.key).parseClaimsJws(token);
        Claims body = claimsJws.getBody();
        return body.getSubject();
    }
}
